package vwg.na.vwm.rh.modulo.pad;

import java.io.IOException;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;

import vwg.na.vwm.rh.modulo.pad.util.ProcesoPlaneacionPersonalAbstract;
import vwg.na.vwm.rh.motorsdk.commons.entidades.Sociedad;
import vwg.na.vwm.rh.motorsdk.commons.entidades.UnidadOrganizativa;
import vwg.na.vwm.rh.motorsdk.modelo.procesos.entidadesgrales.PadDefinicionBudget;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.AjaxBehaviorEvent;

import org.primefaces.event.NodeSelectEvent;

@ManagedBean
@SessionScoped
/**
 * @author Joel Ochoa [joel.ochoa@vw.com.mx]
 */
public class DefinirConstantesMB extends ProcesoPlaneacionPersonalAbstract implements Serializable  {
	
	private static final long serialVersionUID = -4056767177655019213L;

	// No aplica getter y setter porque es para uso interno de la clase
	// establece si es un insert o un update
	private int idDefinicionBudget;
	
    private boolean permiteCaptura;
    private boolean habilitaCapturaCascada;
    
    @ManagedProperty("#{montosMensuales}")
    private MontosMensuales montosBudget;
    
    @ManagedProperty("#{montosMensuales}")
    private MontosMensuales montosTope;
    
	public DefinirConstantesMB() {
	}
	
	@PostConstruct
	private void init(){
		
		// Inicializacion de los nodos del componente Tree
		initNodes();
		
		// Se obtiene todas las sociedades activas
		sociedades = sociedadServicio.getAllActivos();
		
		capturaEjercicio = planeacionPersonalServicio.getCapturaEjercicio();
		
		sociedad = sociedades.get(0).getSociedad();
		processDefinicionBudget();
		
		sumaMontosPorMes(this.montosBudget);
		
	}
	
	public boolean isPermiteCaptura() {
		return permiteCaptura;
	}

	public void setPermiteCaptura(boolean permiteCaptura) {
		this.permiteCaptura = permiteCaptura;
	}

	public boolean isHabilitaCapturaCascada() {
		return habilitaCapturaCascada;
	}

	public void setHabilitaCapturaCascada(boolean habilitaCapturaCascada) {
		this.habilitaCapturaCascada = habilitaCapturaCascada;
	}

	public MontosMensuales getMontosBudget() {
		return montosBudget;
	}


	public void setMontosBudget(MontosMensuales montosBudget) {
		this.montosBudget = montosBudget;
	}

	public MontosMensuales getMontosTope() {
		return montosTope;
	}

	public void setMontosTope(MontosMensuales montosTope) {
		this.montosTope = montosTope;
	}

	public void changeTotalBudget(AjaxBehaviorEvent event) {
		sumaMontosPorMes(this.montosBudget);
	}
	
	private void sumaMontosPorMes(MontosMensuales montos){
		BigDecimal total = new BigDecimal("0");
		
		if(montos != null){
			if(montos.getMontoEnero() != null){
				total = total.add(montos.getMontoEnero());
			}
			if(montos.getMontoFebrero() != null){
				total = total.add(montos.getMontoFebrero());
			}
			if(montos.getMontoMarzo() != null){
				total = total.add(montos.getMontoMarzo());
			}
			if(montos.getMontoAbril() != null){
				total= total.add(montos.getMontoAbril());
			}
			if(montos.getMontoMayo() != null){
				total= total.add(montos.getMontoMayo());
			}
			if(montos.getMontoJunio() != null){
				total= total.add(montos.getMontoJunio());
			}
			if(montos.getMontoJulio() != null){
				total= total.add(montos.getMontoJulio());
			}
			if(montos.getMontoAgosto() != null){
				total= total.add(montos.getMontoAgosto());
			}
			if(montos.getMontoSeptiembre() != null){
				total= total.add(montos.getMontoSeptiembre());
			}
			if(montos.getMontoOctubre() != null){
				total= total.add(montos.getMontoOctubre());
			}
			if(montos.getMontoNoviembre() != null){
				total= total.add(montos.getMontoNoviembre());
			}
			if(montos.getMontoDiciembre() != null){
				total= total.add(montos.getMontoDiciembre());
			}
		}
		
		montos.setMontoTotal(total);
	}
	
	public void saveChanges(ActionEvent actionEvent){
		PadDefinicionBudget definicionBudget = new PadDefinicionBudget();
		String msgSummary;
		String msgDetail;
		Severity severity;
		
		// Valida que el monto capturado junto con los montos de las uo's hermanas
		// no rebasen el monto de la UO padre 
		if(isMontosValidosInsercion()){
			
			if(idDefinicionBudget != -1){
				definicionBudget.setDefinicionBudget(idDefinicionBudget);
			}
			definicionBudget.setBudgetEnero(this.montosBudget.getMontoEnero());
			definicionBudget.setBudgetFebrero(this.montosBudget.getMontoFebrero());
			definicionBudget.setBudgetMarzo(this.montosBudget.getMontoMarzo());
			definicionBudget.setBudgetAbril(this.montosBudget.getMontoAbril());
			definicionBudget.setBudgetMayo(this.montosBudget.getMontoMayo());
			definicionBudget.setBudgetJunio(this.montosBudget.getMontoJunio());
			definicionBudget.setBudgetJulio(this.montosBudget.getMontoJulio());
			definicionBudget.setBudgetAgosto(this.montosBudget.getMontoAgosto());
			definicionBudget.setBudgetSeptiembre(this.montosBudget.getMontoSeptiembre());
			definicionBudget.setBudgetOctubre(this.montosBudget.getMontoOctubre());
			definicionBudget.setBudgetNoviembre(this.montosBudget.getMontoNoviembre());
			definicionBudget.setBudgetDiciembre(this.montosBudget.getMontoDiciembre());
			definicionBudget.setAnio(capturaEjercicio.getAnioCaptura());
			
			if(permiteCaptura){
				definicionBudget.setHabilitadoCaptura(1);
			}else{
				definicionBudget.setHabilitadoCaptura(0);
			}
			
			UnidadOrganizativa uo = (UnidadOrganizativa)selectedNode.getData();
			
			definicionBudget.setUnidadOrganizativa(uo);
			
			definicionBudget.setSociedad(getSociedad(sociedad));
			
			// Falta implementar habilita captura en cascada
			
			if(planeacionPersonalServicio != null){
				msgSummary = "Accion Exitosa";
				severity = FacesMessage.SEVERITY_INFO;
				if(idDefinicionBudget == -1){
					msgDetail = "Definicion registrada";
					planeacionPersonalServicio.saveDefinicionBudget(definicionBudget);
				}else {
					msgDetail = "Definicion actualizada";
					planeacionPersonalServicio.updateDefinicionBudget(definicionBudget);
				}
				
			}else{
				severity = FacesMessage.SEVERITY_FATAL;
				msgSummary = "Accion Fallida";
				msgDetail = "Problema con template de hibernate";
			}
			
		}else{
			severity = FacesMessage.SEVERITY_ERROR;
			msgSummary = "Accion Fallida";
			msgDetail = "La suma de los montos actuales y los montos de la UO's hermanas son mayores al monto de la UO padre";
		}
		
		
		FacesContext context = FacesContext.getCurrentInstance();
		
        //context.addMessage("listGrowl", new FacesMessage(severity, msgSummary, msgDetail));  
		context.addMessage(null, new FacesMessage(severity, msgSummary, msgDetail));
		
	}
	
	private Sociedad getSociedad(String sociedadSelected){
		Sociedad sociedadEncontrada = null;
		for(Sociedad soc : sociedades){
			if(soc.getSociedad().equals(sociedadSelected)){
				sociedadEncontrada = soc;
			}
		}
		
		return sociedadEncontrada;
	}
	
	// Primer parametro la uo de la que se quiere el budget de sus hermanas
	// Segundo parametro la uo padre de uo
	private MontosMensuales getBudgetHermanas(UnidadOrganizativa uo, UnidadOrganizativa uoPadre){
		MontosMensuales monto = new MontosMensuales("0.00"); 
		List<PadDefinicionBudget> defsBudgetHermanas = 
				planeacionPersonalServicio.getDefinicionBudgetHijas(
							uoPadre.getUnidadOrganizativaCorta(), sociedad, capturaEjercicio.getAnioCaptura());
		for(PadDefinicionBudget defHermana : defsBudgetHermanas){
			//Se excluye a uo que en la que se esta trabajando en caso de que exista 
			if(!defHermana.getUnidadOrganizativa().getUnidadOrganizativa().equals(uo.getUnidadOrganizativa())){
				monto.setMontoEnero( monto.getMontoEnero().add( defHermana.getBudgetEnero() ) );
				monto.setMontoFebrero( monto.getMontoFebrero().add( defHermana.getBudgetFebrero() ) );
				monto.setMontoMarzo( monto.getMontoMarzo().add( defHermana.getBudgetMarzo() ) );
				monto.setMontoAbril( monto.getMontoAbril().add( defHermana.getBudgetAbril() ) );
				monto.setMontoMayo( monto.getMontoMayo().add( defHermana.getBudgetMayo() ) );
				monto.setMontoJunio( monto.getMontoJunio().add( defHermana.getBudgetJunio() ) );
				monto.setMontoJulio( monto.getMontoJulio().add( defHermana.getBudgetJulio() ) );
				monto.setMontoAgosto( monto.getMontoAgosto().add( defHermana.getBudgetAgosto() ) );
				monto.setMontoSeptiembre( monto.getMontoSeptiembre().add( defHermana.getBudgetSeptiembre() ) );
				monto.setMontoOctubre( monto.getMontoOctubre().add( defHermana.getBudgetOctubre() ) );
				monto.setMontoNoviembre( monto.getMontoNoviembre().add( defHermana.getBudgetNoviembre() ) );
				monto.setMontoDiciembre( monto.getMontoDiciembre().add( defHermana.getBudgetDiciembre() ) );
			}
			
		}
		return monto;
	}
	
	private boolean isMontosValidosInsercion(){
		boolean montosValidos = true;
		
		UnidadOrganizativa uo = (UnidadOrganizativa)selectedNode.getData();
		UnidadOrganizativa uoPadre = (UnidadOrganizativa)selectedNode.getParent().getData();
		
		if(!uoPadre.getUnidadOrganizativa().equals("03000000")){
			MontosMensuales montosHermanas = getBudgetHermanas(uo, uoPadre);
			
			// Se suman a los montos de las uo's hermanas los montos capturados
			montosHermanas.setMontoEnero(montosHermanas.getMontoEnero().add(this.getMontosBudget().getMontoEnero()));
			montosHermanas.setMontoFebrero(montosHermanas.getMontoFebrero().add(this.getMontosBudget().getMontoFebrero()));
			montosHermanas.setMontoMarzo(montosHermanas.getMontoMarzo().add(this.getMontosBudget().getMontoMarzo()));
			montosHermanas.setMontoAbril(montosHermanas.getMontoAbril().add(this.getMontosBudget().getMontoAbril()));
			montosHermanas.setMontoMayo(montosHermanas.getMontoMayo().add(this.getMontosBudget().getMontoMayo()));;
			montosHermanas.setMontoJunio(montosHermanas.getMontoJunio().add(this.getMontosBudget().getMontoJunio()));
			montosHermanas.setMontoJulio(montosHermanas.getMontoJulio().add(this.getMontosBudget().getMontoJulio()));
			montosHermanas.setMontoAgosto(montosHermanas.getMontoAgosto().add(this.getMontosBudget().getMontoAgosto()));
			montosHermanas.setMontoSeptiembre(montosHermanas.getMontoSeptiembre().add(this.getMontosBudget().getMontoSeptiembre()));
			montosHermanas.setMontoOctubre(montosHermanas.getMontoOctubre().add(this.getMontosBudget().getMontoOctubre()));
			montosHermanas.setMontoNoviembre(montosHermanas.getMontoNoviembre().add(this.getMontosBudget().getMontoNoviembre()));
			montosHermanas.setMontoDiciembre(montosHermanas.getMontoDiciembre().add(this.getMontosBudget().getMontoDiciembre()));
			
			MontosMensuales montoMovimientosPadre =
				planeacionPersonalServicio.getMontosMensualesMovimientosPadre(
					uoPadre.getUnidadOrganizativa(), sociedad, capturaEjercicio.getAnioCaptura());
			
			MontosMensuales montosTotal = new MontosMensuales();
			montosTotal.setMontoEnero(montosHermanas.getMontoEnero().add(montoMovimientosPadre.getMontoEnero()));
			montosTotal.setMontoFebrero(montosHermanas.getMontoFebrero().add(montoMovimientosPadre.getMontoFebrero()));
			montosTotal.setMontoMarzo(montosHermanas.getMontoMarzo().add(montoMovimientosPadre.getMontoMarzo()));
			montosTotal.setMontoAbril(montosHermanas.getMontoAbril().add(montoMovimientosPadre.getMontoAbril()));
			montosTotal.setMontoMayo(montosHermanas.getMontoMayo().add(montoMovimientosPadre.getMontoMayo()));
			montosTotal.setMontoJunio(montosHermanas.getMontoJunio().add(montoMovimientosPadre.getMontoJunio()));
			montosTotal.setMontoJulio(montosHermanas.getMontoJulio().add(montoMovimientosPadre.getMontoJulio()));
			montosTotal.setMontoAgosto(montosHermanas.getMontoAgosto().add(montoMovimientosPadre.getMontoAgosto()));
			montosTotal.setMontoSeptiembre(montosHermanas.getMontoSeptiembre().add(montoMovimientosPadre.getMontoSeptiembre()));
			montosTotal.setMontoOctubre(montosHermanas.getMontoOctubre().add(montoMovimientosPadre.getMontoOctubre()));
			montosTotal.setMontoNoviembre(montosHermanas.getMontoNoviembre().add(montoMovimientosPadre.getMontoNoviembre()));
			montosTotal.setMontoDiciembre(montosHermanas.getMontoDiciembre().add(montoMovimientosPadre.getMontoDiciembre()));
			
			PadDefinicionBudget definicionBudgetPadre =
				planeacionPersonalServicio.getDefinicionBudget(
					uoPadre.getUnidadOrganizativa(), sociedad, capturaEjercicio.getAnioCaptura());
			
			// Compara si el budget mensual total de las uo's hijas es mayor estricto al budget mensual de la uo padre
			if(montosTotal.getMontoEnero().compareTo(definicionBudgetPadre.getBudgetEnero()) > 0){
				montosValidos = false;
			}
			if(montosTotal.getMontoFebrero().compareTo(definicionBudgetPadre.getBudgetFebrero()) > 0){
				montosValidos = false;
			}
			if(montosTotal.getMontoMarzo().compareTo(definicionBudgetPadre.getBudgetMarzo()) > 0){
				montosValidos = false;
			}
			if(montosTotal.getMontoAbril().compareTo(definicionBudgetPadre.getBudgetAbril()) > 0){
				montosValidos = false;
			}
			if(montosTotal.getMontoMayo().compareTo(definicionBudgetPadre.getBudgetMayo()) > 0){
				montosValidos = false;
			}
			if(montosTotal.getMontoJunio().compareTo(definicionBudgetPadre.getBudgetJunio()) > 0){
				montosValidos = false;
			}
			if(montosTotal.getMontoJulio().compareTo(definicionBudgetPadre.getBudgetJulio()) > 0){
				montosValidos = false;
			}
			if(montosTotal.getMontoAgosto().compareTo(definicionBudgetPadre.getBudgetAgosto()) > 0){
				montosValidos = false;
			}
			if(montosTotal.getMontoSeptiembre().compareTo(definicionBudgetPadre.getBudgetSeptiembre()) > 0){
				montosValidos = false;
			}
			if(montosTotal.getMontoOctubre().compareTo(definicionBudgetPadre.getBudgetOctubre()) > 0){
				montosValidos = false;
			}
			if(montosTotal.getMontoNoviembre().compareTo(definicionBudgetPadre.getBudgetNoviembre()) > 0){
				montosValidos = false;
			}
			if(montosTotal.getMontoDiciembre().compareTo(definicionBudgetPadre.getBudgetDiciembre()) > 0){
				montosValidos = false;
			}
		}
		return montosValidos;
	}
	
	
	public void onNodeSelect(NodeSelectEvent event) {
		processDefinicionBudget();
    }
	
	public void processChangeSociedad(){
		processDefinicionBudget();
	}
	
	private void processDefinicionBudget(){
		resetForm();
		
		activateCapturaPanel(true);
		UnidadOrganizativa uo = (UnidadOrganizativa)selectedNode.getData();
		UnidadOrganizativa uoPadre = (UnidadOrganizativa)selectedNode.getParent().getData();
        // Id de la UO - Presidencia Ejecutiva 03000000
        // valida que la uoPadre de la nueva uo no sea presidencia ejecutiva
        if(!uoPadre.getUnidadOrganizativa().equals("03000000")){
        	PadDefinicionBudget definicionBudgetPadre = 
        			planeacionPersonalServicio.getDefinicionBudget(
        						uoPadre.getUnidadOrganizativa(), sociedad, capturaEjercicio.getAnioCaptura());
        	
        	if(definicionBudgetPadre != null){// Existe la definicion de budget padre
        		//setTope(definicionBudgetPadre);
        		MontosMensuales montoHermanas = getBudgetHermanas(uo, uoPadre);
        		MontosMensuales montoMovimientosPadre = planeacionPersonalServicio.getMontosMensualesMovimientosPadre(
        			uoPadre.getUnidadOrganizativa(), sociedad, capturaEjercicio.getAnioCaptura());
        		setTope(definicionBudgetPadre, montoHermanas, montoMovimientosPadre);
        		processDefinicionBudgetNuevaUO();
        	}else{// No existe la definicion de budget padre
        		// debe implementar deshabilitar los campos
        		activateCapturaPanel(false);
        	}
        }else{// la uo padre de la nueva uo es Presidencia ejecutiva
        	resetTope();
        	processDefinicionBudgetNuevaUO();
        }
	}
	
	private void processDefinicionBudgetNuevaUO(){
		UnidadOrganizativa uoNueva = (UnidadOrganizativa)selectedNode.getData();
		PadDefinicionBudget definicionBudgetNueva = 
				planeacionPersonalServicio.getDefinicionBudget(
    						uoNueva.getUnidadOrganizativa(), sociedad, capturaEjercicio.getAnioCaptura());
		
		// Ya existe la definicion de budget
		if(definicionBudgetNueva != null){
			loadDefinicionBudget(definicionBudgetNueva);
			this.idDefinicionBudget = definicionBudgetNueva.getDefinicionBudget();
		}else{ // No existe una captura en blanco
			this.idDefinicionBudget = -1;
			resetForm();
		}
	}
	
	private void setTope(PadDefinicionBudget defBudgetPadre, MontosMensuales montoHermanas, MontosMensuales montoMovimientosPadre){
		montosTope.setMontoEnero(
				defBudgetPadre.getBudgetEnero().subtract(
						montoHermanas.getMontoEnero()).subtract(montoMovimientosPadre.getMontoEnero()));
		montosTope.setMontoFebrero(
				defBudgetPadre.getBudgetFebrero().subtract(
						montoHermanas.getMontoFebrero()).subtract(montoMovimientosPadre.getMontoFebrero()));
		montosTope.setMontoMarzo(
				defBudgetPadre.getBudgetMarzo().subtract(
						montoHermanas.getMontoMarzo()).subtract(montoMovimientosPadre.getMontoMarzo()));
		montosTope.setMontoAbril(
				defBudgetPadre.getBudgetAbril().subtract(
						montoHermanas.getMontoAbril()).subtract(montoMovimientosPadre.getMontoAbril()));
		montosTope.setMontoMayo(
				defBudgetPadre.getBudgetMayo().subtract(
						montoHermanas.getMontoMayo()).subtract(montoMovimientosPadre.getMontoMayo()));
		montosTope.setMontoJunio(
				defBudgetPadre.getBudgetJunio().subtract(
						montoHermanas.getMontoJunio()).subtract(montoMovimientosPadre.getMontoJunio()));
		montosTope.setMontoJulio(
				defBudgetPadre.getBudgetJulio().subtract(
						montoHermanas.getMontoJulio()).subtract(montoMovimientosPadre.getMontoJulio()));
		montosTope.setMontoAgosto(
				defBudgetPadre.getBudgetAgosto().subtract(
						montoHermanas.getMontoAgosto()).subtract(montoMovimientosPadre.getMontoAgosto()));
		montosTope.setMontoSeptiembre(
				defBudgetPadre.getBudgetSeptiembre().subtract(
						montoHermanas.getMontoSeptiembre()).subtract(montoMovimientosPadre.getMontoSeptiembre()));
		montosTope.setMontoOctubre(
				defBudgetPadre.getBudgetOctubre().subtract(
						montoHermanas.getMontoOctubre()).subtract(montoMovimientosPadre.getMontoOctubre()));
		montosTope.setMontoNoviembre(
				defBudgetPadre.getBudgetNoviembre().subtract(
						montoHermanas.getMontoNoviembre()).subtract(montoMovimientosPadre.getMontoNoviembre()));
		montosTope.setMontoDiciembre(
				defBudgetPadre.getBudgetDiciembre().subtract(
						montoHermanas.getMontoDiciembre()).subtract(montoMovimientosPadre.getMontoDiciembre()));
		
		sumaMontosPorMes(this.montosTope);
	}
	
	private void resetTope(){
		
		this.montosTope = new MontosMensuales();
		
	}
	
	private void loadDefinicionBudget(PadDefinicionBudget defBudget){
		
		this.montosBudget.setMontoEnero(defBudget.getBudgetEnero());
		this.montosBudget.setMontoFebrero(defBudget.getBudgetFebrero());
		this.montosBudget.setMontoMarzo(defBudget.getBudgetMarzo());
		this.montosBudget.setMontoAbril(defBudget.getBudgetAbril());
		this.montosBudget.setMontoMayo(defBudget.getBudgetMayo());
		this.montosBudget.setMontoJunio(defBudget.getBudgetJunio());
		this.montosBudget.setMontoJulio(defBudget.getBudgetJulio());
		this.montosBudget.setMontoAgosto(defBudget.getBudgetAgosto());
		this.montosBudget.setMontoSeptiembre(defBudget.getBudgetSeptiembre());
		this.montosBudget.setMontoOctubre(defBudget.getBudgetOctubre());
		this.montosBudget.setMontoNoviembre(defBudget.getBudgetNoviembre());
		this.montosBudget.setMontoDiciembre(defBudget.getBudgetDiciembre());
		
		sumaMontosPorMes(this.montosBudget);
		
		if(defBudget.getHabilitadoCaptura() == 1){
			this.permiteCaptura = true;
		} else{
			this.permiteCaptura = false;
		}
	}
	
	private void resetForm(){
		
		this.montosBudget = new MontosMensuales();
		
		this.permiteCaptura = false;
		this.habilitaCapturaCascada = false;
	}
	
	private void writeObject(java.io.ObjectOutputStream out)
		     throws IOException{
		out.defaultWriteObject();
	}
	
	private void readObject(java.io.ObjectInputStream in)
		     throws IOException, ClassNotFoundException{
		in.defaultReadObject();
	}
	
}
